package controller

import (
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"time"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

// Server 本地文件服务
type Server struct {
	Base
	path string
	port int
}

func NewServer() *Server {
	return &Server{}
}

// get请求
func (s *Server) get(c *gin.Context) {
	//假设token失效
	s.log(fmt.Sprintf("Token : %s", c.Request.Header.Get("token")))
	//c.JSON(http.StatusOK, s.res(NoLoginCode, "请先登录", nil))
	c.JSON(http.StatusOK, s.success("这个是本地自定义的get请求，你也可以调用第三方API"))
}

// post请求
func (s *Server) post(c *gin.Context) {
	c.JSON(http.StatusOK, s.success("这个是本地自定义的post请求，你也可以调用第三方API"))
}

// file 本地文件转为http流
func (s *Server) file(c *gin.Context) {
	c.File(c.Query("filename"))
}

// upload
func (s *Server) upload(c *gin.Context) {
	// 单文件
	file, _ := c.FormFile("file")
	saveName := fmt.Sprintf("%d_%s", time.Now().Unix(), file.Filename)
	dst := s.pathConvert(fmt.Sprintf("%s\\%s", s.path, saveName))
	_ = c.SaveUploadedFile(file, dst)
	c.JSON(200, s.success(gin.H{
		"name": file.Filename,
		"dst":  dst,
		"ext":  path.Ext(file.Filename),
		"path": saveName,
		"url":  fmt.Sprintf("http://localhost:%d/preview/%s", s.port, saveName),
		"size": file.Size,
	}))
}

// proxy 代理外部API请求
func (s *Server) proxy(c *gin.Context) {
	type kv struct {
		Enabled bool   `json:"enabled"`
		Key     string `json:"key"`
		Value   string `json:"value"`
	}
	var req struct {
		Method          string            `json:"method"`
		URL             string            `json:"url"`
		Headers         map[string]string `json:"headers"`
		Body            string            `json:"body"`
		BodyType        string            `json:"bodyType"`
		FormData        []kv              `json:"formData"`
		Urlencoded      []kv              `json:"urlencoded"`
		Timeout         int               `json:"timeout"`
		FollowRedirects bool              `json:"followRedirects"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusOK, s.error("参数错误"))
		return
	}
	if req.URL == "" {
		c.JSON(http.StatusOK, s.error("请求地址不能为空"))
		return
	}
	if req.Method == "" {
		req.Method = "GET"
	}
	timeout := time.Duration(req.Timeout)
	if timeout <= 0 {
		timeout = 15000
	}
	client := &http.Client{Timeout: timeout * time.Millisecond}
	if !req.FollowRedirects {
		client.CheckRedirect = func(_ *http.Request, _ []*http.Request) error { return http.ErrUseLastResponse }
	}
	// Build request body based on bodyType
	var bodyReader io.Reader
	var contentType string

	bt := strings.ToLower(strings.TrimSpace(req.BodyType))
	switch bt {
	case "json":
		bodyReader = strings.NewReader(req.Body)
		contentType = "application/json"
	case "form-urlencoded":
		v := url.Values{}
		for _, p := range req.Urlencoded {
			if p.Enabled && p.Key != "" {
				v.Add(p.Key, p.Value)
			}
		}
		bodyReader = strings.NewReader(v.Encode())
		contentType = "application/x-www-form-urlencoded"
	case "form": // multipart/form-data (text fields only)
		pr, pw := io.Pipe()
		mw := multipart.NewWriter(pw)
		go func() {
			for _, f := range req.FormData {
				if f.Enabled && f.Key != "" {
					_ = mw.WriteField(f.Key, f.Value)
				}
			}
			_ = mw.Close()
			_ = pw.Close()
		}()
		bodyReader = pr
		contentType = mw.FormDataContentType()
	case "raw":
		fallthrough
	default:
		bodyReader = strings.NewReader(req.Body)
	}

	httpReq, err := http.NewRequest(req.Method, req.URL, bodyReader)
	if err != nil {
		c.JSON(http.StatusOK, s.error(err.Error()))
		return
	}
	for k, v := range req.Headers {
		httpReq.Header.Set(k, v)
	}
	if contentType != "" && httpReq.Header.Get("Content-Type") == "" {
		httpReq.Header.Set("Content-Type", contentType)
	}
	start := time.Now()
	resp, err := client.Do(httpReq)
	if err != nil {
		c.JSON(http.StatusOK, s.error(err.Error()))
		return
	}
	defer resp.Body.Close()
	s.log(fmt.Sprintf("响应状态码：%d", resp.StatusCode))
	b, _ := io.ReadAll(resp.Body)
	c.JSON(http.StatusOK, s.success(gin.H{
		"status":     resp.StatusCode,
		"statusText": resp.Status,
		"headers":    resp.Header,
		"body":       string(b),
		"durationMs": time.Since(start).Milliseconds(),
		"finalURL":   resp.Request.URL.String(),
	}))
}

// apiTesterList 已保存的API集合列表
func (s *Server) apiTesterList(c *gin.Context) {
	file := s.pathConvert(fmt.Sprintf("%s\\apiTester.json", s.getAppPath()))
	var data []interface{}
	b, err := os.ReadFile(file)
	if err == nil && len(b) > 0 {
		_ = json.Unmarshal(b, &data)
	}
	c.JSON(http.StatusOK, s.success(gin.H{"collections": data}))
}

// apiTesterSave 保存API集合列表
func (s *Server) apiTesterSave(c *gin.Context) {
	var req struct {
		Collections []interface{} `json:"collections"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusOK, s.error("参数错误"))
		return
	}
	file := s.pathConvert(fmt.Sprintf("%s\\apiTester.json", s.getAppPath()))
	b, _ := json.Marshal(req.Collections)
	_ = os.WriteFile(file, b, os.ModePerm)
	c.JSON(http.StatusOK, s.success("保存成功"))
}

// start 启动时加载
func (s *Server) start(port int) *Server {
	s.path = s.pathExist(s.pathConvert(fmt.Sprintf("%s\\files", s.getAppPath())))
	s.port = port
	go func() {
		r := gin.Default()
		r.Use(cors.New(cors.Config{
			AllowAllOrigins:  true,
			AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
			AllowHeaders:     []string{"*"},
			ExposeHeaders:    []string{"Content-Length", "Authorization", "Content-Type"},
			AllowCredentials: true,
			MaxAge:           12 * time.Hour},
		))

		//API路由
		r.GET("/get", s.get)
		r.POST("/post", s.post)
		r.POST("/proxy", s.proxy)
		r.GET("/apiTester/list", s.apiTesterList)
		r.POST("/apiTester/save", s.apiTesterSave)
		r.Any("/file", s.file)
		r.Static("/preview", s.path)
		r.POST("/upload", s.upload)

		_ = r.Run(fmt.Sprintf(":%d", s.port))
	}()
	return s
}
